package cn.jianyongjie.basic.service.impl;

import cn.jianyongjie.basic.dto.VerificationCode;
import cn.jianyongjie.basic.exception.CustomException;
import cn.jianyongjie.basic.constant.BaseConstant;
import cn.jianyongjie.basic.service.IVerifyCodeService;
import cn.jianyongjie.basic.utils.SendSmsUtils;
import cn.jianyongjie.basic.utils.VerifyCodeUtils;
import cn.jianyongjie.user.domain.User;
import cn.jianyongjie.user.mapper.UserMapper;
import com.mysql.jdbc.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
* @Description: TODO
* @Author: JianYongJie
* @Version: 1.0
* @Date:  2022/5/7 17:30
*/
@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {


    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;


    /*
    * @Title: VerifyCodeServiceImpl
    * @Description: 获取图形验证码
    * @Author: JianYongJie
    * @Version: 1.0
    * @Date:  2022/5/7 17:30
    * @Parameters: * @param
    * @Return java.lang.String
    */
    @Override
    public String getVerificationCode(String key) {

        // 获取随机验证码，长度为4
        String s = VerifyCodeUtils.generateVerifyCode(4);
        // 将验证码存储到redis，并且设置5分钟过期时间，使用前端传递的UUID值做为key值进行储存
        redisTemplate.opsForValue().set(key,s,5,TimeUnit.MINUTES);
        // 使用JDK自带的2D引擎将获取到的验证码编写成画，再编成字符串传递到前端
        String s1 = VerifyCodeUtils.VerifyCode(90, 45, s);
        return s1;
    }


    /*
    * @Title: VerifyCodeServiceImpl
    * @Description: 发送注册短信验证码
    * @Author: JianYongJie
    * @Version: 1.0
    * @Date:  2022/5/8 14:14
    * @Parameters: * @param verificationCode
    * @Return void
    */
    @Override
    public void sendSmsCode(VerificationCode code) {

        // 查询手机号是否已经被注册
        User user = userMapper.LoadByPhone(code.getPhone());
        // 唯一标识不能为空
        String type = code.getType();

        if (user!=null){
            throw new CustomException("该手机号已经被注册了，请登录");
        }

        if (type==null){
            throw new CustomException("唯一标识不能为空");
        }

        if (type.equals("register")){
            // 注册
            registerLogin(code);

        }else if(type.equals("binder")){

            // 绑定手机登录
            binderLogin(code);
        }


    }

    /*
    * @Title: VerifyCodeServiceImpl
    * @Description: 公共获取验证码方法
    * @Author: JianYongJie
    * @Version: 1.0
    * @Date:  2022/5/12 20:26
    * @Parameters: * @param
    * @Return void
    */
    void ShareVerification(String key,String phone){

        // 使用全局常量类拼接电话得到拼接后的参数
        String businessKey = key;
        // 使用拼接后的参数查询redis里面的短信验证码
        Object smsCode = redisTemplate.opsForValue().get(businessKey);
        String smsKey;
        // 判断是否为null
        if (smsCode!=null){
            // 如果不为null就代表还没有过期
            // 获取短信验证码的时间戳
            // 这里的1就是获取冒号后面的数据，我们设置的数据就是创建验证码的当前时间戳
            Long aLong = Long.valueOf(smsCode.toString().split(":")[1]);
            // 判断是否已经过了一分钟
            if (System.currentTimeMillis()-aLong<1*60*1000){
                // 没有过一分钟就直接给用户提示
                throw new CustomException("验证码不能重复获取，请登录");
            }else {
                // 已经过了一分钟就将原来的验证码赋值给抽出的字符串，在外面重新设置有效时间
                // 这里的0代表全部参数都赋值给抽出的字符串
                smsKey = smsCode.toString().split(":")[0];
                System.out.println("验证码更新");
            }

        }else {
            // 如果为null就代表短信验证码已经过期了，就重新获取验证码
            smsKey = VerifyCodeUtils.generateVerifyCode(4);
        }

        // 新增一个字符串，将抽出来的短信验证码加上分号和时间戳赋值给它
        String registerValue = smsKey+":"+System.currentTimeMillis();
        // 最后保存到redis,key值为全局常量和电话拼接的字符串，value值为新增的字符串，设置3分钟有效时间
        redisTemplate.opsForValue().set(businessKey,registerValue,3,TimeUnit.MINUTES);

        // 最后发送短信
        // SendSmsUtils.sms(phone,"注册成功这是你的验证码"+smsKey+",请尽快使用");

        System.out.println("注册成功这是你的验证码:"+smsKey+",请尽快使用");
    }


    /*
    * @Title: VerifyCodeServiceImpl
    * @Description: 手机绑定登录流程
    * @Author: JianYongJie
    * @Version: 1.0
    * @Date:  2022/5/12 20:20
    * @Parameters: * @param code
    * @Return void
    */
    private void binderLogin(VerificationCode code) {
        String phone = code.getPhone();
        String key = BaseConstant.REGISTER_BINDER_CODE+ phone;
        ShareVerification(key,phone);
    }

    /*
    * @Title: VerifyCodeServiceImpl
    * @Description: 注册流程
    * @Author: JianYongJie
    * @Version: 1.0
    * @Date:  2022/5/12 20:20
    * @Parameters: * @param code
    * @Return void
    */
    private void registerLogin(VerificationCode code) {
        // 抽取重复代码
        String phone = code.getPhone();
        String imageCodeValue = code.getImageCodeValue();
        String imageCodeKey = code.getImageCodeKey();

        // 将前端用户传递的数据进行空校验
        if (imageCodeValue==null){
            throw new CustomException("请输入图形验证码");
        }

        if (phone==null){
            throw new CustomException("请输入手机号码");
        }

        if (imageCodeKey==null){
            throw new CustomException("图形验证码获取失败，请重新获取");
        }

        // 通过图形验证码的key值获取验证码数据
        Object value = redisTemplate.opsForValue().get(imageCodeKey);

        // 判断图形验证码是否已经失效了
        if (value!=null){
            // 如果不为空就判断用户输入的验证码是否一致，并且不区分大小写
            if (!imageCodeValue.toString().equalsIgnoreCase(value.toString())){
                throw new CustomException("请输入正确的图形验证码");
            }

        }else {
            // 如果验证码已经失效了,就提醒用户重新获取验证码
            throw new CustomException("图形验证码已经失效，请重新获取");
        }

        String key = BaseConstant.REGISTER_VERIFICATION_CODE+ phone;
        ShareVerification(key,phone);
    }

}
